﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Diagnostics;

#if USE_DYNAMIC_SHAREPOINT || USE_REFLECTION_SHAREPOINT
#else
using Microsoft.SharePoint;
#endif

namespace System.Data.SharePoint
{
    public class SharePointConnection : DbConnection
    {
#if USE_DYNAMIC_SHAREPOINT || USE_REFLECTION_SHAREPOINT
        public const string SHAREPOINT_ASSEMBLY_NAME = "Microsoft.SharePoint.dll";
        public const string SHAREPOINT_SPSITE_TYPE_NAME = "Microsoft.SharePoint.SPSite";
        public const string SHAREPOINT_SPQUERY_TYPE_NAME = "Microsoft.SharePoint.SPQuery";
        public const string SHAREPOINT_SPFIELDTYPE_TYPE_NAME = "Microsoft.SharePoint.SPFieldType";


        /// <summary>
        /// Gets the specific name Type.
        /// </summary>
        /// <param name="instance">Type.</param>
        /// <param name="typeName">Type name.</param>
        /// <returns>Type.</returns>
        public static System.Type GetType(System.Type type, string typeName)
        {
            typeName = typeName.Trim();
            System.Reflection.Assembly assembly;
            if (typeName.IndexOf(",") >= 0)
            {
                string[] names = typeName.Split(',');
                assembly = System.Reflection.Assembly.LoadFrom(names[0]);
                typeName = names[1];
            }
            else
            {
                assembly = type.Assembly;
            }

            return assembly.GetType(typeName);
        }

        public static object CreateSPSite(string requestUrl)
        {
            string SPSiteTypeName = SHAREPOINT_SPSITE_TYPE_NAME + ", " + SHAREPOINT_ASSEMBLY_NAME;
            Type SPSiteType = GetType(typeof(SharePointConnection), SPSiteTypeName);
            if (SPSiteType != null)
            {
                return System.Activator.CreateInstance(SPSiteType, requestUrl);
            }
            return null;
        }

        public static object CreateSPQuery()
        {
            string SPQueryTypeName = SHAREPOINT_SPQUERY_TYPE_NAME + ", " + SHAREPOINT_ASSEMBLY_NAME;
            Type SPQueryType = GetType(typeof(SharePointConnection), SPQueryTypeName);
            if (SPQueryType != null)
            {
                return System.Activator.CreateInstance(SPQueryType);
            }
            return null;
        }

        private static Dictionary<int, Type> _SPFieldTypes;
        public static Dictionary<int, Type> SPFieldTypes
        {
            get
            {
                if (_SPFieldTypes == null)
                {
                    lock (typeof(SharePointConnection))
                    {
                        if (_SPFieldTypes == null)
                        {
                            _SPFieldTypes = new Dictionary<int, Type>();
                            try
                            {
                                string SPFieldTypeTypeName = SHAREPOINT_SPFIELDTYPE_TYPE_NAME + ", " + SHAREPOINT_ASSEMBLY_NAME;
                                Type SPFieldTypeType = GetType(typeof(SharePointConnection), SPFieldTypeTypeName);
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "Guid"), typeof(Guid));
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "Counter"), typeof(long));
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "Text"), typeof(string));
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "DateTime"), typeof(DateTime));
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "Boolean"), typeof(bool));
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "Integer"), typeof(int));
                                _SPFieldTypes.Add((int)Enum.Parse(SPFieldTypeType, "Number"), typeof(decimal));
                            }
                            catch(Exception ex)
                            {
                                Debug.WriteLine(ex);
                            }
                        }
                    }
                }
                return _SPFieldTypes;
            }
        }

        public static Type GetFieldType(int fieldType)
        {
            if (SPFieldTypes.ContainsKey(fieldType))
            {
                return SPFieldTypes[fieldType];
            }
            else
            {
                return typeof(string);
            }
        }
#endif

        public SharePointConnection()
        {
            // TODO:
        }

#if USE_DYNAMIC_SHAREPOINT
        public SharePointConnection(string connectionString)
        {
            this._connectionString = connectionString;
            this._sharePointSite = CreateSPSite(this._connectionString);
            this._sharePointWeb = this._sharePointSite.OpenWeb();
        }
#elif USE_REFLECTION_SHAREPOINT
#else
        public SharePointConnection(string connectionString)
        {
            this._connectionString = connectionString;
            this._sharePointSite = new SPSite(this._connectionString);
            this._sharePointWeb = this._sharePointSite.OpenWeb();
        }
#endif

        public static string CombineUrl(string baseUrl, string relativeUrl)
        {
            if (!string.IsNullOrEmpty(baseUrl))
            {
                if (!string.IsNullOrEmpty(relativeUrl))
                {
                    if (baseUrl.EndsWith("/"))
                    {
                        if (relativeUrl.StartsWith("/"))
                        {
                            if (relativeUrl.Length > 1)
                            {
                                return baseUrl + relativeUrl.Substring(1);
                            }
                            else
                            {
                                return baseUrl;
                            }
                        }
                        else
                        {
                            return baseUrl + relativeUrl;
                        }
                    }
                    else
                    {
                        if (relativeUrl.StartsWith("/"))
                        {
                            return baseUrl + relativeUrl;
                        }
                        else
                        {
                            return baseUrl + "/" + relativeUrl;
                        }
                    }
                }
                return baseUrl;
            }
            return relativeUrl;
        }

        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            throw new NotImplementedException();
        }

        public override void ChangeDatabase(string databaseName)
        {
            throw new NotImplementedException();
        }

        public override void Close()
        {
            this._state = ConnectionState.Closed;
        }

        private string _connectionString;
        public override string ConnectionString
        {
            get
            {
                return this._connectionString;
            }
            set
            {
                this._connectionString = value;
            }
        }

        protected override DbCommand CreateDbCommand()
        {
            return new SharePointCommand(null, this);
        }

        public override string DataSource
        {
            get { throw new NotImplementedException(); }
        }

        public override string Database
        {
            get { throw new NotImplementedException(); }
        }

        public override void Open()
        {
            this._state = ConnectionState.Open;
        }

        public override string ServerVersion
        {
            get { throw new NotImplementedException(); }
        }

        private ConnectionState _state;
        public override ConnectionState State
        {
            get { return this._state; }
        }


#if USE_DYNAMIC_SHAREPOINT
        private dynamic _sharePointSite;
        public dynamic SharePointSite
        {
            get { return _sharePointSite; }
            set { _sharePointSite = value; }
        }

        private dynamic _sharePointWeb;
        public dynamic SharePointWeb
        {
            get { return _sharePointWeb; }
            set { _sharePointWeb = value; }
        }
#elif USE_REFLECTION_SHAREPOINT
#else
        private SPSite _sharePointSite;
        public SPSite SharePointSite
        {
            get { return _sharePointSite; }
            set { _sharePointSite = value; }
        }

        private SPWeb _sharePointWeb;
        public SPWeb SharePointWeb
        {
            get { return _sharePointWeb; }
            set { _sharePointWeb = value; }
        }
#endif


#if USE_DYNAMIC_SHAREPOINT
        public DataTable GetTables()
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(new DataColumn("ID", typeof(Guid)));
            dataTable.Columns.Add(new DataColumn("Title", typeof(string)));
            dataTable.Columns.Add(new DataColumn("BaseType", typeof(string)));
            dataTable.Columns.Add(new DataColumn("RootFolderUrl", typeof(string)));
            foreach (dynamic list in this._sharePointWeb.Lists)
            {
                System.Data.DataRow dataRow = dataTable.NewRow();
                dataRow["ID"] = list.ID;
                dataRow["Title"] = list.Title;
                dataRow["BaseType"] = list.BaseType.ToString();
                dataRow["RootFolderUrl"] = list.RootFolder.Url;
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }

        public DataTable GetTable(string listUrl)
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(new DataColumn("ID", typeof(Guid)));
            dataTable.Columns.Add(new DataColumn("Title", typeof(string)));
            dataTable.Columns.Add(new DataColumn("InternalName", typeof(string)));
            dataTable.Columns.Add(new DataColumn("FieldType", typeof(Type)));
            dataTable.Columns.Add(new DataColumn("Required", typeof(bool)));
            UriBuilder uriBuilder = new UriBuilder();
            dynamic list = this._sharePointWeb.GetList(CombineUrl(this._sharePointWeb.ServerRelativeUrl, listUrl));
            foreach (dynamic field in list.Fields)
            {
                System.Data.DataRow dataRow = dataTable.NewRow();
                dataRow["ID"] = field.Id;
                dataRow["Title"] = field.Title;
                dataRow["InternalName"] = field.InternalName;
                dataRow["FieldType"] = GetFieldType(field.Type);
                dataRow["Required"] = field.Required;
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }
#elif USE_REFLECTION_SHAREPOINT
#else
        public DataTable GetTables()
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(new DataColumn("ID", typeof(Guid)));
            dataTable.Columns.Add(new DataColumn("Title", typeof(string)));
            dataTable.Columns.Add(new DataColumn("BaseType", typeof(string)));
            dataTable.Columns.Add(new DataColumn("RootFolderUrl", typeof(string)));
            foreach (SPList list in this._sharePointWeb.Lists)
            {
                System.Data.DataRow dataRow = dataTable.NewRow();
                dataRow["ID"] = list.ID;
                dataRow["Title"] = list.Title;
                dataRow["BaseType"] = list.BaseType.ToString();
                dataRow["RootFolderUrl"] = list.RootFolder.Url;
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }

        public DataTable GetTable(string listUrl)
        {
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add(new DataColumn("ID", typeof(Guid)));
            dataTable.Columns.Add(new DataColumn("Title", typeof(string)));
            dataTable.Columns.Add(new DataColumn("InternalName", typeof(string)));
            dataTable.Columns.Add(new DataColumn("FieldType", typeof(Type)));
            dataTable.Columns.Add(new DataColumn("Required", typeof(bool)));
            UriBuilder uriBuilder = new UriBuilder();
            SPList list = this._sharePointWeb.GetList(CombineUrl(this._sharePointWeb.ServerRelativeUrl, listUrl));
            foreach (SPField field in list.Fields)
            {
                System.Data.DataRow dataRow = dataTable.NewRow();
                dataRow["ID"] = field.Id;
                dataRow["Title"] = field.Title;
                dataRow["InternalName"] = field.InternalName;
                dataRow["FieldType"] = GetFieldType(field.Type);
                dataRow["Required"] = field.Required;
                dataTable.Rows.Add(dataRow);
            }
            return dataTable;
        }
#endif
        
#if USE_DYNAMIC_SHAREPOINT
        private Type GetFieldType(dynamic fieldType)
        {
            return GetFieldType((int)fieldType);
        }

        public dynamic GetSharePointList(string listUrl)
        {
            return this.SharePointWeb.GetList(SharePointConnection.CombineUrl(this.SharePointWeb.ServerRelativeUrl, listUrl));
        }
#elif USE_REFLECTION_SHAREPOINT
#else
        private Type GetFieldType(SPFieldType fieldType)
        {
            switch (fieldType)
            {
                case SPFieldType.Guid:
                    {
                        return typeof(Guid);
                        break;
                    }
                case SPFieldType.Counter:
                    {
                        return typeof(long);
                        break;
                    }
                case SPFieldType.Text:
                    {
                        return typeof(string);
                        break;
                    }
                case SPFieldType.DateTime:
                    {
                        return typeof(DateTime);
                        break;
                    }
                case SPFieldType.Boolean:
                    {
                        return typeof(bool);
                        break;
                    }
                case SPFieldType.Integer:
                    {
                        return typeof(int);
                        break;
                    }
                case SPFieldType.Number:
                    {
                        return typeof(decimal);
                        break;
                    }
                default:
                    {
                        return typeof(string);
                    }
            }
            return null;
        }

        public SPList GetSharePointList(string listUrl)
        {
            return this.SharePointWeb.GetList(SharePointConnection.CombineUrl(this.SharePointWeb.ServerRelativeUrl, listUrl));
        }
#endif
    }
}
